using System;
using System.Collections.Generic;
using System.Text;

namespace TileGert
{
  /// <summary>
  /// GertVector defines a two dimensional Vector with all standard vector math routines.
  /// </summary>
  public class GertVector
  {
    /// <summary>
    /// The internal field for the x component of the vector.
    /// </summary>
    protected float _x = 0.0f;
    /// <summary>
    /// The internal field for the y component of the vector.
    /// </summary>
    protected float _y = 0.0f;

    /// <summary>
    /// Creates a new GertVector with X and Y set to 0.
    /// </summary>
    public GertVector()
    {
    }

    /// <summary>
    /// Creates a new GertVector and initializes X and Y with the given values.
    /// </summary>
    /// <param name="x">The x component.</param>
    /// <param name="y">The y component.</param>
    public GertVector(float x, float y)
    {
      _x = x;
      _y = y;
    }

    /// <summary>
    /// Gets the X component of the vector.
    /// </summary>
    public float X
    {
      get { return _x; }
      set { _x = value; }
    }

    /// <summary>
    /// Gets the Y component of this vector.
    /// </summary>
    public float Y
    {
      get { return _y; }
      set { _y = value; }
    }

    /// <summary>
    /// Gets the magnitude (length) of the vector by using the pythogarean theorem.
    /// </summary>
    public float Magnitude
    {
      get { return (float)Math.Sqrt(_x * _x + _y * _y); }
    }

    /// <summary>
    /// Adds the values of the given vector to this vector.
    /// </summary>
    /// <param name="other">The vector to be added.</param>
    public void Add(GertVector other)
    {
      _x += other._x;
      _y += other._y;
    }

    /// <summary>
    /// Subtracts the values of the given vector from this vector.
    /// </summary>
    /// <param name="other">The vector to be subtracted.</param>
    public void Subtract(GertVector other)
    {
      _x -= other._x;
      _y -= other._y;
    }

    /// <summary>
    /// Normalizes this Vector. That is, X and Y are scaled so the magnitude of the vector is 1.0.
    /// </summary>
    public void Normalize()
    {
      float magnitude = Magnitude;
      _x /= magnitude;
      _y /= magnitude;
    }

    /// <summary>
    /// Scales the components of this vector by the given factor.
    /// </summary>
    /// <param name="factor">The scaling factor.</param>
    public void Scale(float factor)
    {
      _x *= factor;
      _y *= factor;
    }

    /// <summary>
    /// Calculates the dot/scalar product of this and the given vector.
    /// NOTE: The vectors have to normalized!
    /// </summary>
    /// <param name="other">The other vector.</param>
    /// <returns>The dot/scalar product of the two vectors.</returns>
    public float DotProcduct(GertVector other)
    {
      return _x * other._x + _y * other._y;
    }

    /// <summary>
    /// Adds the components of the two given vectors and returns the result.
    /// </summary>
    /// <param name="vec1">The first vector.</param>
    /// <param name="vec2">The second vector.</param>
    /// <returns>A new vector with the result of the addition.</returns>
    public static GertVector Add(GertVector vec1, GertVector vec2)
    {
      return new GertVector(vec1._x + vec2._x, vec1._y + vec2._y);
    }

    /// <summary>
    /// Subtracts the components of the two given vectors and returns the result.
    /// </summary>
    /// <param name="vec1">The first vector.</param>
    /// <param name="vec2">The second vector.</param>
    /// <returns>A new vector with the result of the subtraction.</returns>
    public static GertVector Subtract(GertVector vec1, GertVector vec2)
    {
      return new GertVector(vec1._x - vec2._x, vec1._y - vec2._y);
    }

    /// <summary>
    /// Normalizes the given vector and returns the result as a new vector.
    /// </summary>
    /// <param name="vec">The vector to be normalized.</param>
    /// <returns>The normalized vector.</returns>
    public static GertVector Normalize(GertVector vec)
    {
      float magnitude = vec.Magnitude;
      return new GertVector(vec._x / magnitude, vec._y / magnitude);
    }

    /// <summary>
    /// Scales the components of given vector by the given factor and returns the result as a new vector.
    /// </summary>
    /// <param name="vec">The vector to be scaled.</param>
    /// <param name="factor">The scaling factor.</param>
    /// <returns>The scaled vector.</returns>
    public static GertVector Scale(GertVector vec, float factor)
    {
      return new GertVector(vec._x * factor, vec._y * factor);
    }

    /// <summary>
    /// Calculates the dot/scalar product of the two given vectors.
    /// NOTE: The vectors have to be normalized!
    /// </summary>
    /// <param name="vec1">The first vector.</param>
    /// <param name="vec2">The second vector.</param>
    /// <returns>The dot/scalar product of the two given vectors.</returns>
    public static float DotProduct(GertVector vec1, GertVector vec2)
    {
      return vec1._x * vec2._x + vec1._y * vec2._y;
    }

  }
}
